package protocol

import (
	"context"
	"fmt"
	"net/http"
	"time"

	"gitee.com/fzh-show/mcenter/swagger"
	"github.com/infraboard/mcube/ioc"
	"github.com/infraboard/mcube/ioc/apidoc"
	"github.com/infraboard/mcube/ioc/health"

	"gitee.com/fzh-show/mcenter/conf"
	"gitee.com/fzh-show/mcenter/logger"

	restful "github.com/emicklei/go-restful/v3"
)

// 如果http 服务器使用哪个路由, 当作参数传递进来
func NewHttp() *Http {
	r := restful.DefaultContainer
	restful.DefaultResponseContentType(restful.MIME_JSON)
	restful.DefaultRequestContentType(restful.MIME_JSON)
	// 跨域中间件CORS
	cors := restful.CrossOriginResourceSharing{
		AllowedHeaders: []string{".*"},
		AllowedDomains: []string{".*"},
		AllowedMethods: []string{"HEAD",
			"OPTIONS", "GET", "POST", "PUT", "PATCH", "DELETE"},
		CookiesAllowed: false,
		Container:      r,
	}
	// 使用Filter加载中间件,相当于gin里面的use
	r.Filter(cors.Filter)
	return &Http{
		apiDocPath: "/apidocs.json",
		router:     r,
		server: &http.Server{
			// 服务器的监听地址
			Addr: conf.C().Http.Address(),
			// 配置http server使用的路由
			// 如果是其他框架,这里传递其他框架的路由
			Handler: r,
			// client ---> server服务端读取客户端的请求超时时间
			ReadTimeout: 5 * time.Second,
			// server ---> client 服务端响应客户端的超时时间
			WriteTimeout: 5 * time.Second,
		},
	}
}

type Http struct {
	server     *http.Server
	router     *restful.Container
	apiDocPath string
}

// /mcenter/api/v1
func (h *Http) PathPrefix() string {
	return fmt.Sprintf("/%s/api", conf.C().App.Name)
}

func (h *Http) Start() error {
	// 装载子服务路由
	ioc.LoadGoRestfulApi(h.PathPrefix(), h.router)
	logger.L().Debug().Msgf("loaded apis: %s", ioc.ListApiObjectNames())
	logger.L().Debug().Msgf("http server: %s", conf.C().Http.Address())

	// api doc
	h.router.Add(apidoc.APIDocs(h.apiDocPath, swagger.Docs))
	logger.L().Debug().Msgf("Swagger API Doc 访问地址: http://%s%s", conf.C().Http.Address(), h.apiDocPath)

	// HealthCheck
	hc := health.NewDefaultHealthChecker()
	h.router.Add(hc.WebService())
	logger.L().Debug().Msgf("健康检查地址: http://%s%s", conf.C().Http.Address(), hc.HealthCheckPath)
	for _, ws := range h.router.RegisteredWebServices() {
		fmt.Println(ws.RootPath())
	}
	// http
	return h.server.ListenAndServe()
}

func (h *Http) Stop(ctx context.Context) {
	//http 服务优雅关闭, 先关闭监听,新的请求无法进入,等待老的请求处理完成
	// 字节接收来自操作系统的信号量 来决定你的服务器是否需要关闭
	// nginx reload, os reload sign, config.reload
	// 当os termnial sign, 过了terminal的超时时间会直接kill掉
	h.server.Shutdown(ctx)
}
